﻿using Controller.Enum;
using Controller.Model;
using Controller.Utils;
using ControllerManageServer.ActionModel;
using ControllerManageServer.ActionModel.Aioi;
using ControllerManageServer.ActionModel.AioiNW;
using ControllerManageServer.Handler;
using ControllerManageServer.LabelDevice.Aioi;
using ControllerManageServer.Packet;
using Leeder.Logger;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ControllerManageServer.Controller.Aioi
{
    internal class AioiController : SocketServerBaseController
    {
        #region 变量声明

        /// <summary>
        /// 是否停止
        /// </summary>
        private bool isStop;
        /// <summary>
        /// 序列号
        /// </summary>
        private int serialNo;
        /// <summary>
        /// 生成数据锁
        /// </summary>
        private object generateDataLocker;
        /// <summary>
        /// 数据处理线程
        /// </summary>
        private Thread DataControlThread;
        /// <summary>
        /// 接收数据队列
        /// </summary>
        private ConcurrentQueue<byte[]> receiveDataQueue;
        /// <summary>
        /// 发送数据字典,序列号和对应的发送数据信息,用于追溯
        /// </summary>
        private ConcurrentDictionary<int, byte[]> sendDataDictionary;
        /// <summary>
        /// 应答报文字典,下发后响应的为应答报文,指令如o n n1
        /// key为序列号,value为对应的指令报文包模型
        /// </summary>
        private ConcurrentDictionary<int, AioiActionPacketModel> ackDictionary;
        /// <summary>
        /// 消息字典,控制器主动上送的为消息报文,如按下标签后反馈的信号,指令如t
        /// key为序列号,value为对应的指令报文包模型
        /// </summary>
        private ConcurrentDictionary<int, AioiActionPacketModel> messageDictionary;
        /// <summary>
        /// 序列响应字典,用于重发,
        /// 当序列号为101的指令发送失败,之后发102成功,
        /// 这里其实就是把102和101作一个关联,只要有一个序列号返回o指令即代表该操作成功
        /// </summary>
        private ConcurrentDictionary<int, AioiSendSerialConnectionModel> serialRespondDictionary;
        /// <summary>
        /// 设备地址和哪个DPS客户端的映射表
        /// </summary>
        private ConcurrentDictionary<string, string> deviceAddressDictionary;
        /// <summary>
        /// 设备地址连接列表锁
        /// </summary>
        private object connectionAddressListLocker;
        /// <summary>
        /// 设备地址连接列表
        /// </summary>
        private List<string> connectionAddressList;
        /// <summary>
        /// 连接状态
        /// </summary>
        private bool connectionState;
        /// <summary>
        /// 定时检测设备返回的定时器,1秒检测一次
        /// </summary>
        //private Timer checkDeviceResultTimer;

        #endregion 变量声明

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iIp"></param>
        /// <param name="iPort"></param>
        public AioiController(string iIp, int iPort) : base(iIp, iPort, EquipmentBrandEnum.AIOI)
        {
        }

        /// <summary>
        /// 启动
        /// </summary>
        public override void Start()
        {
            connectionState = true;
            isStop = false;
            serialNo = 0;
            connectionAddressListLocker = new object();
            generateDataLocker = new object();
            receiveDataQueue = new ConcurrentQueue<byte[]>();
            ackDictionary = new ConcurrentDictionary<int, AioiActionPacketModel>();
            messageDictionary = new ConcurrentDictionary<int, AioiActionPacketModel>();
            serialRespondDictionary = new ConcurrentDictionary<int, AioiSendSerialConnectionModel>();
            sendDataDictionary = new ConcurrentDictionary<int, byte[]>();
            deviceAddressDictionary = new ConcurrentDictionary<string, string>();
            connectionAddressList = new List<string>();
            // 检测设备返回定时器
            //checkDeviceResultTimer = new Timer(new TimerCallback(CheckDeviceResult), null, 1000,1000);
            // 数据处理线程
            DataControlThread = new Thread(DataControlFunction) { IsBackground = true };
            DataControlThread.Start();

            base.Start();
        }

        /// <summary>
        /// 停止
        /// </summary>
        public override void Stop()
        {
            base.Stop();
            isStop = true;
            generateDataLocker = null;
            ackDictionary.Clear();
            messageDictionary.Clear();
            serialRespondDictionary.Clear();
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="iDatas"></param>
        public override void ReceiveData(byte[] iDatas)
        {
            CheckReturn(iDatas);

            receiveDataQueue.Enqueue(iDatas);
        }

        /// <summary>
        /// 校验和返回
        /// </summary>
        /// <param name="iDatas"></param>
        private void CheckReturn(byte[] iDatas) {

            if (iDatas[0] != AioiSocketClientHandler.HEAT || iDatas[iDatas.Length - 1] != AioiSocketClientHandler.TAIL)
            {
                logObj.Error($"报文异常(帧头帧尾错误),重置连接! 数据报文:{ByteUtils.ByteArrayToHexString(iDatas)}\r\n");
                return;
            }
            string temp = DefaultEncoding.GetString(iDatas, 1, iDatas.Length - 2);// 去头去尾后的字符串
            AioiActionPacketModel packetModel = new AioiActionPacketModel();
            packetModel.DataBuffer = iDatas;
            packetModel.Unserialize(temp);
            if (packetModel.CmdType == "t")
            {
                #region 回答收到通知
                //回答收到通知
                List<byte> retData = new List<byte>();
                try
                {
                    byte[] retArr = DefaultEncoding.GetBytes("O");
                    retData.Add(AioiSocketClientHandler.HEAT);
                    retData.AddRange(DefaultEncoding.GetBytes(temp.Substring(0, 3)));
                    retData.AddRange(DefaultEncoding.GetBytes(retArr.Length.ToString().PadLeft(4, '0')));
                    retData.AddRange(retArr);
                    retData.Add(AioiSocketClientHandler.TAIL);
                    retArr = retData.ToArray();
                    // 立即回应
                    Controller.SendData(retArr);
                    logObj.Debug($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} <> [Aoio][{ipAddress}:{port}]应答(通知)：{ByteUtils.ByteArrayToHexString(retArr)}\t{ByteUtils.ByteArrayToAsciiString(retArr)}\r\n");
                }
                catch (Exception ex)
                {
                    logObj.Error(ExceptionType.ServiceException, ex, "回答收到通知失败!\r\n");
                }
                #endregion 回答收到通知
            }
        }

        /// <summary>
        /// 控制器连接状态修改
        /// </summary>
        /// <param name="iState"></param>
        protected override void ControllerConnectionStateChange(bool iState)
        {
            connectionState = iState;
            List<string> deleteList = new List<string>();
            foreach (string key in connectionAddressList)
            {
                if (deviceAddressDictionary.Values.Contains(key))
                {
                    SendDataToClientByKey(key, new ControllerStatePacketModel { ControllerKey = $"{ipAddress}:{port}", State = connectionState ? ControllerStateEnum.NORMAL : ControllerStateEnum.OFFLINE });
                }
                else
                {
                    deleteList.Add(key);
                }
            }
            lock (connectionAddressListLocker)
            {
                deleteList.ForEach(p => connectionAddressList.Remove(p));
            }
        }

        /// <summary>
        /// 生成发送数据
        /// </summary>
        /// <param name="iDatas">指令数据</param>
        /// <returns></returns>
        public override byte[] GenerateSendData(byte[] iDatas)
        {
            List<byte> datas = new List<byte>();
            datas.Add(AioiSocketClientHandler.HEAT);
            int currentSerialNo = GetSecNo();
            datas.AddRange(DefaultEncoding.GetBytes(currentSerialNo.ToString().PadLeft(3, '0')));
            datas.AddRange(DefaultEncoding.GetBytes(iDatas.Length.ToString().PadLeft(4, '0')));
            datas.AddRange(iDatas);
            datas.Add(AioiSocketClientHandler.TAIL);

            if (!sendDataDictionary.ContainsKey(currentSerialNo))
            {
                sendDataDictionary.TryAdd(currentSerialNo, datas.ToArray());
            }
            else
            {
                sendDataDictionary[currentSerialNo] = datas.ToArray();
            }
            // 重置序列号
            //if (iDatas.Length == 1 && iDatas[0] == 'Z') {
            //    serialNo = 0;
            //}

            return sendDataDictionary[currentSerialNo];
        }

        /// <summary>
        /// 发送失败,第iCount发送iData数据失败
        /// </summary>
        /// <param name="iCount">从1开始的索引</param>
        /// <param name="iData">发送的数据</param>
        public override void SendFailure(int iCount, byte[] iData)
        {
            base.SendFailure(iCount, iData);
            // 发送的连番号
            int sendSerialNo = int.Parse(DefaultEncoding.GetString(iData, 1, 3));
            AddSerialCorrelation(sendSerialNo, sendSerialNo - iCount - 1);
        }

        /// <summary>
        /// 数据处理函数
        /// </summary>
        private void DataControlFunction()
        {
            byte[] dataArr;
            while (!isStop)
            {
                if (receiveDataQueue.IsEmpty)
                {
                    Thread.Sleep(IdleIntervalTime);
                }
                if (receiveDataQueue.TryDequeue(out dataArr))
                {
                    ParseData(dataArr);
                }
                //Thread.Sleep(100);
            }
        }

        /// <summary>
        /// 解析数据
        /// </summary>
        private void ParseData(byte[] iData)
        {
            if (iData[0] != AioiSocketClientHandler.HEAT || iData[iData.Length - 1] != AioiSocketClientHandler.TAIL)
            {
                logObj.Error($"报文异常(帧头帧尾错误),重置连接! 数据报文:{ByteUtils.ByteArrayToHexString(iData)}\r\n");
                return;
            }
            string temp = DefaultEncoding.GetString(iData, 1, iData.Length - 2);// 去头去尾后的字符串
            AioiActionPacketModel packetModel = new AioiActionPacketModel();
            packetModel.DataBuffer = iData;
            packetModel.Unserialize(temp);
            switch (packetModel.CmdType)
            {
                case "o":  //控制器应答成功
                    {
                        packetModel.State = true;
                        ackDictionary.TryAdd(packetModel.SerialNo, packetModel);
                        // 有一个成功则删除所有关联
                        DeleteSerialCorrelation(packetModel.SerialNo);
                    }
                    break;
                case "a":// 返回电子标签状态
                    {
                        packetModel.State = true;
                        ackDictionary.TryAdd(packetModel.SerialNo, packetModel);
                        LabelStatePacketModel model = new LabelStatePacketModel { ControllerKey = $"{ipAddress}:{port}" };
                        GetLabelState(temp, ref model);
                        SendDataToClient(model.Address, model);
                        // 有一个成功则删除所有关联
                        DeleteSerialCorrelation(packetModel.SerialNo);
                    }
                    break;
                case "n": // 控制器应答 标签异常
                case "n1":// 控制器应答 序列异常
                    {
                        string msg;
                        ControllerExceptionCodeEnum code = ControllerExceptionCodeEnum.LABEL_EXCEPTION;
                        packetModel.State = false;
                        ackDictionary.TryAdd(packetModel.SerialNo, packetModel);
                        // 发送多条相同数据,但还有没返回的数据
                        if (FindSerialCorrelation(packetModel.SerialNo).Count > 1)
                        {
                            if (packetModel.CmdType.Equals("n1"))
                            {
                                msg = "序列异常";
                                code = ControllerExceptionCodeEnum.SEQUENCE_EXCEPTION;
                            }
                            else
                            {
                                msg = "标签异常";
                                code = ControllerExceptionCodeEnum.LABEL_EXCEPTION;
                            }
                            logObj.Error($"{msg} {ByteUtils.ByteArrayToHexString(iData)} {ByteUtils.ByteArrayToAsciiString(iData)}");
                            serialRespondDictionary[packetModel.SerialNo].ConnectionSerialNo = -1;
                            break;
                        }
                        if (serialRespondDictionary.ContainsKey(packetModel.SerialNo))
                        {
                            serialRespondDictionary[packetModel.SerialNo].ConnectionSerialNo = -1;
                        }
                        if (sendDataDictionary.ContainsKey(packetModel.SerialNo))
                        {
                            // 从追溯报文字典中找出对应的设备地址
                            string errorMsg = $"{DateTime.Now} <> 控制器应答 --> ";
                            errorMsg += packetModel.CmdType.Equals("n") ? "标签异常!" : "序列异常!";
                            errorMsg += ByteUtils.ByteArrayToAsciiString(sendDataDictionary[packetModel.SerialNo]);
                            logObj.Error($"{errorMsg}\r\n");
                            string sendStr = DefaultEncoding.GetString(sendDataDictionary[packetModel.SerialNo], 1, sendDataDictionary[packetModel.SerialNo].Length - 2);// 去头去尾后的字符串
                            AioiActionPacketModel sendPacket = new AioiActionPacketModel();
                            packetModel.DataBuffer = iData;
                            sendPacket.Unserialize(sendStr);
                            if (!string.IsNullOrEmpty(sendPacket.Address))
                            {
                                // 发送异常信息到连接客户端
                                SendDataToClient(sendPacket.Address, new ExceptionInfoPacketModel { Address = sendPacket.Address, ExceptionCode = code, ControllerKey = $"{ipAddress}:{port}"});
                            }
                        }
                        // 删除对应的所有关联
                        DeleteSerialCorrelation(packetModel.SerialNo);
                    }
                    break;
                case "t"://电子标签等设备应答数据
                    {

                        logObj.Info($"(10000)收到电子标签应答->解析,设备地址:{packetModel.Address}");
                        messageDictionary.TryAdd(packetModel.SerialNo, packetModel);
                        TriggerLabelPacketModel model = new TriggerLabelPacketModel { Address = packetModel.Address, ControllerKey = $"{ipAddress}:{port}" };
                        // 获取标签应答信息
                        GetLabelAck(temp, ref model);
                        SendDataToClient(model.Address, model);

                        //#region 回答收到通知
                        ////回答收到通知
                        //List<byte> retData = new List<byte>();
                        //try
                        //{
                        //    byte[] retArr = DefaultEncoding.GetBytes("O");
                        //    retData.Add(AioiSocketClientHandler.HEAT);
                        //    retData.AddRange(DefaultEncoding.GetBytes(temp.Substring(0, 3)));
                        //    retData.AddRange(DefaultEncoding.GetBytes(retArr.Length.ToString().PadLeft(4, '0')));
                        //    retData.AddRange(retArr);
                        //    retData.Add(AioiSocketClientHandler.TAIL);
                        //    retArr = retData.ToArray();
                        //    // 立即回应
                        //    Controller.SendData(retArr);
                        //    logObj.Debug($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} <> [Aoio][{ipAddress}:{port}]应答(通知)：{ByteUtils.ByteArrayToHexString(retArr)}\t{ByteUtils.ByteArrayToAsciiString(retArr)}\r\n");
                        //}
                        //catch (Exception ex)
                        //{
                        //    logObj.Error(ExceptionType.ServiceException, ex, "回答收到通知失败!\r\n");
                        //}
                        //#endregion 回答收到通知
                    }
                    break;
                default:
                    logObj.Error($"无效的命令码!数据报文:{ByteUtils.ByteArrayToHexString(iData)}\r\n");
                    break;
            }
        }

        /// <summary>
        /// 获取标签应答数据
        /// </summary>
        /// <param name="iData">去头去尾后的字符串</param>
        /// <param name="iAddress">地址</param>
        /// <param name="iControllerKey">控制器的键</param>
        private List<TriggerLabelPacketModel> GetLabelAck(string iData, string iAddress, string iControllerKey)
        {
            List<TriggerLabelPacketModel> result = new List<TriggerLabelPacketModel>();
            // 0050015t000200100900
            int pos = 8;// 前三位是连番号,接着四位是地址,再加上一位是一个字符的a,第8位标签地址的起始位置
            while (pos < iData.Length)
            {
                TriggerLabelPacketModel model = new TriggerLabelPacketModel
                {
                    Address = iData.Substring(pos, 4),
                    ControllerKey = iControllerKey
                };
                pos += 4;
                try
                {
                    //iModel.Address = iData.Substring(pos, 4);
                    string state = iData.Substring(pos, 2);
                    pos += 2;
                    // 01为异常
                    if (!"00".Equals(state) /*&& !"01".Equals(state)*/)
                    {
                        model.State = DeviceStateEnum.ABNORMAL;
                        result.Add(model);
                        continue;
                    }
                    if (iData.Length <= pos) { result.Add(model); break; };
                    switch (iData[pos])
                    {
                        case ':':// :40033<------0E2034416721001840950B856>
                            { // UHF RF-ID的响应
                                pos += 2;// :4
                                int dataLength = int.Parse(iData.Substring(pos, 4));// 0033
                                pos += 4;
                                if (dataLength != 33)
                                {
                                    model.State = DeviceStateEnum.ABNORMAL;
                                    result.Add(model);
                                    return result;
                                }
                                pos++;// <
                                model.DisplayData = iData.Substring(pos, 6);
                                pos += 6;
                                char moduleState = iData[pos++];
                                if (moduleState == '1')
                                {
                                    model.ModuleState = LabelModelStateEnum.RW_ABNORMAL;
                                }
                                else if (moduleState == '2')
                                {
                                    model.ModuleState = LabelModelStateEnum.FORCE_CANCEL;
                                }
                                else
                                {
                                    model.ModuleState = LabelModelStateEnum.NORMAL;
                                }
                                model.EpcData = iData.Substring(pos, 24);
                                pos += 25;
                            }
                            break;
                        case '<':// 0050015t000200<500357>
                            {
                                pos++;
                                if (iData.Contains(":"))
                                {
                                    if (iData[pos] != ':')
                                    {
                                        model.DisplayData = iData.Substring(pos, 5);
                                        pos += 6;
                                    }
                                    pos++;// 跳过:号
                                    if (iData.Length <= pos) { result.Add(model); return result; }
                                    char moduleState = iData[pos++];
                                    if (iData[pos] == '>') { result.Add(model); return result; }
                                    if (moduleState == '0')
                                    {
                                        model.ModuleState = LabelModelStateEnum.GET_UID_FAILED;
                                    }
                                    else if ('1' == moduleState)
                                    {
                                        model.ModuleState = LabelModelStateEnum.GET_UID_SUCCESS;
                                    }
                                    else if ('2' == moduleState)
                                    {
                                        model.ModuleState = LabelModelStateEnum.RF_ID_ABNORMAL;
                                    }
                                    else
                                    {
                                        model.ModuleState = LabelModelStateEnum.FORCE_CANCEL;
                                    }
                                    model.EpcData = iData.Substring(pos, 8);
                                    pos += 8;
                                }
                                else if (iData.Contains('-'))
                                {
                                    // 翻页专用,预留先不处理
                                }
                                else
                                {
                                    if (iData.Length - pos == 7 && iData[iData.Length - 1] == '>')
                                    {
                                        if ("50".Equals(iData.Substring(pos, 2)))
                                        { // 电压数据
                                            pos += 2;
                                            model.Message = iData.Substring(pos, 4);
                                            model.State = DeviceStateEnum.VOLTAGE_DATA;
                                        }
                                    }
                                }
                            }
                            break;
                        default:
                            break;
                    }
                    result.Add(model);
                }
                catch (Exception ex)
                {
                    model.State = DeviceStateEnum.ANALYSIS_ABNORMAL;
                    model.Message = $"解析异常.(0x02){iData}(0x03)";
                    result.Add(model);
                    break;
                }
            }
            return result;
        }

        /// <summary>
        /// 获取标签应答数据
        /// </summary>
        /// <param name="iData">去头去尾后的字符串</param>
        /// <param name="iModel"></param>
        private void GetLabelAck(string iData, ref TriggerLabelPacketModel iModel)
        {
            try
            {
                // 0050015t000200100900
                int pos = 8;// 前三位是连番号,接着四位是地址,再加上一位是一个字符的a,第8位标签地址的起始位置

                iModel.Address = iData.Substring(pos, 4);
                pos += 4;
                string state = iData.Substring(pos, 2);
                pos += 2;
                // 01为异常
                if ("01".Equals(state) /*&& !"01".Equals(state)*/)
                {
                    iModel.State = DeviceStateEnum.ABNORMAL;
                }
                if (iData.Length <= pos) return;
                pos++;
                switch (iData[pos - 1])
                {
                    case ':':
                        { // UHF RF-ID的响应
                            pos++;// 4
                            int dataLength = int.Parse(iData.Substring(pos, 4));// 0033
                            pos += 4;
                            if (dataLength != 33)
                            {
                                iModel.State = DeviceStateEnum.ABNORMAL;
                                return;
                            }
                            pos++;// <
                            iModel.DisplayData = iData.Substring(pos, 6);
                            pos += 6;
                            char moduleState = iData[pos++];
                            if (moduleState == '1')
                            {
                                iModel.ModuleState = LabelModelStateEnum.RW_ABNORMAL;
                            }
                            else if (moduleState == '2')
                            {
                                iModel.ModuleState = LabelModelStateEnum.FORCE_CANCEL;
                            }
                            else
                            {
                                iModel.ModuleState = LabelModelStateEnum.NORMAL;
                            }
                            iModel.EpcData = iData.Substring(pos, 24);
                            pos += 25;
                        }
                        break;
                    case '<':// 0050015t000200<500357>
                        {
                            if (iData.Contains(":"))
                            {
                                if (iData[pos] != ':')
                                {
                                    iModel.DisplayData = iData.Substring(pos, 5);
                                    pos += 6;
                                }
                                pos++;// 跳过:号
                                if (iData.Length <= pos) return;
                                char moduleState = iData[pos++];
                                if (iData[pos] == '>') return;
                                if (moduleState == '0')
                                {
                                    iModel.ModuleState = LabelModelStateEnum.GET_UID_FAILED;
                                }
                                else if ('1' == moduleState)
                                {
                                    iModel.ModuleState = LabelModelStateEnum.GET_UID_SUCCESS;
                                }
                                else if ('2' == moduleState)
                                {
                                    iModel.ModuleState = LabelModelStateEnum.RF_ID_ABNORMAL;
                                }
                                else
                                {
                                    iModel.ModuleState = LabelModelStateEnum.FORCE_CANCEL;
                                }
                                iModel.EpcData = iData.Substring(pos, 8);
                                pos += 8;
                            }
                            else if (iData.Contains('-'))
                            {
                                // 翻页专用,预留先不处理
                            }
                            else {
                                if (iData.Length - pos == 7 && iData[iData.Length - 1] == '>') {
                                    if ("50".Equals(iData.Substring(pos, 2))) { // 电压数据
                                        pos += 2;
                                        iModel.Message = iData.Substring(pos, 4);
                                        iModel.State = DeviceStateEnum.VOLTAGE_DATA;
                                    }
                                }
                            }
                        }
                        break;
                    default:
                        iModel.State = DeviceStateEnum.ANALYSIS_ABNORMAL;
                        iModel.Message = $"解析异常.(0x02){iData}(0x03)";
                        break;
                }
            }
            catch (Exception ex)
            {
                iModel.State = DeviceStateEnum.ANALYSIS_ABNORMAL;
                iModel.Message = $"解析异常.(0x02){iData}(0x03)";
            }
            return;
        }

        /// <summary>
        /// 获取标签状态
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iModel">标签状态</param>
        private void GetLabelState(string iData, ref LabelStatePacketModel iModel)
        {
            int len = int.Parse(iData.Substring(3, 4));
            int pos = 8;// 前三位是连番号,接着四位是地址,再加上一位是一个字符的a,第8位标签地址的起始位置
            iModel.Address = iData.Substring(pos, 4);
            pos += 4;
            iModel.LabelStateType = (EquipmentRunStateEnum)iData[pos++];
            if (len == 8)
            {
                iModel.KeyIncrease = (iData[pos] & (0x01 << 1)) > 0;
                iModel.KeyDecrease = (iData[pos++] & (0x01 << 2)) > 0;
                iModel.KeyConfirm = (iData[pos] & (0x01 << 1)) > 0;
                iModel.KeyFn = (iData[pos] & (0x01 << 2)) > 0;
            }

        }

        /// <summary>
        /// 获取序列号
        /// </summary>
        /// <returns></returns>
        private int GetSecNo()
        {
            lock (generateDataLocker)
            {
                int ret = serialNo;
                serialNo++;
                serialNo = serialNo % 1000;
                return ret;
            }
        }

        /// <summary>
        /// 添加序列响应关联
        /// </summary>
        /// <param name="key">当前连番号</param>
        /// <param name="value">发送失败的连番号</param>
        private void AddSerialCorrelation(int key, int value)
        {
            if (!serialRespondDictionary.ContainsKey(key)) return;
            serialRespondDictionary[key].ConnectionSerialNo = value;
            serialRespondDictionary[key].SendDateTime = DateTime.Now;
        }

        /// <summary>
        /// 删除关联
        /// </summary>
        /// <param name="key"></param>
        private void DeleteSerialCorrelation(int key)
        {
            if (!serialRespondDictionary.ContainsKey(key)) return;
            // 找到是同数据不同连番号的起始连番号
            int value = serialRespondDictionary[key].ConnectionSerialNo == key ? key : serialRespondDictionary[key].ConnectionSerialNo;
            for (int i = 0; i < 1000; i++)
            {
                if (serialRespondDictionary.ContainsKey(i) && serialRespondDictionary[i].ConnectionSerialNo == value) serialRespondDictionary[i].ConnectionSerialNo = -1;
            }
        }

        /// <summary>
        /// 查找出关联的序列号
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private List<int> FindSerialCorrelation(int key)
        {
            List<int> result = new List<int>();
            if (!serialRespondDictionary.ContainsKey(key)) return result;
            // 找到是同数据不同连番号的起始连番号
            int value = serialRespondDictionary[key].ConnectionSerialNo == key ? key : serialRespondDictionary[key].ConnectionSerialNo;
            for (int i = 0; i < 1000; i++)
            {
                if (serialRespondDictionary[i].ConnectionSerialNo == value) result.Add(i);
            }
            return result;
        }

        /// <summary>
        /// 设置发送数据
        /// </summary>
        /// <param name="key">哪个DPS客户端发过来的</param>
        /// <param name="iPacket"></param>
        public override void SetSendData(string key, ServerPacketModel iPacket)
        {
            // 如果没在连接列表中,则添加
            if (!connectionAddressList.Contains(key))
            {
                lock (connectionAddressListLocker)
                {
                    connectionAddressList.Add(key);
                }
                SendDataToClientByKey(key, new ControllerStatePacketModel { State = connectionState ? ControllerStateEnum.NORMAL : ControllerStateEnum.OFFLINE, ControllerKey = $"{ipAddress}:{port}" });
            }
            BaseLabelDevice device = null;
            // 获取设备地址
            List<string> deviceAddressList = new List<string>();
            switch (iPacket.CmdType)
            {
                case CommunicationCmdTypeEnum.CANCEL:
                    device = new BaseLabelDevice();
                    deviceAddressList.AddRange(((CancelPacketModel)iPacket).AddressList);
                    break;
                case CommunicationCmdTypeEnum.ACTION:
                    device = GetLabelDeviceActionInfo(iPacket);
                    deviceAddressList.AddRange(((ActionPacketModel)iPacket).AddressList);
                    break;
                case CommunicationCmdTypeEnum.GET_LABEL_STATE:
                    device = new BaseLabelDevice();
                    deviceAddressList.Add(((GetLabelStatePacketModel)iPacket).Address);
                    break;
                case CommunicationCmdTypeEnum.REGISTRATION_DEVICE:
                    deviceAddressList.AddRange(((RegistrationDevicePacketModel)iPacket).AddressList);
                    break;
                case CommunicationCmdTypeEnum.GET_LABEL_VOLTAGE:
                    device = GetLabelDeviceActionInfo(iPacket);
                    deviceAddressList.Add(((GetDeviceVoltagePacketModel)iPacket).Address);
                    break;
                default:
                    {
                        logObj.Error($"DPS服务数据包收到无效的类型![{iPacket.CmdType}]\r\n");
                        return;
                    }
            }
            // 将设备地址和下发的key做映射,该设备地址反馈时回传用
            foreach (string address in deviceAddressList)
            {
                if (!deviceAddressDictionary.ContainsKey(address)) deviceAddressDictionary.TryAdd(address, key);
                else deviceAddressDictionary[address] = key;
            }
            // 注册设备只需要存映射就行了
            if (iPacket.CmdType == CommunicationCmdTypeEnum.REGISTRATION_DEVICE) return;
            if (iPacket.CmdType == CommunicationCmdTypeEnum.CANCEL)
            {
                string longAddress = string.Empty;
                for (int i = 0; i < deviceAddressList.Count; i++)
                {
                    if (i % 10 == 0)
                    {
                        if (!string.IsNullOrEmpty(longAddress))
                            SetSendData(device.Cancel(longAddress));
                        longAddress = string.Empty;
                    }
                    longAddress += deviceAddressList[i];
                }
                if (!string.IsNullOrEmpty(longAddress))
                    SetSendData(device.Cancel(longAddress));
                return;
            }
            // 遍历每个设备
            foreach (string deviceAddress in deviceAddressList)
            {
                device.Address = deviceAddress;
                switch (iPacket.CmdType)
                {
                    case CommunicationCmdTypeEnum.CANCEL:
                        SetSendData(device.Cancel());
                        break;
                    case CommunicationCmdTypeEnum.ACTION:
                        ActionPacketModel packetModel = (ActionPacketModel)iPacket;
                        ActionModelAbstract actionModel = GetActionModel(packetModel.LabelType);
                        actionModel.ToActionModel(packetModel);
                        // 先取消，再下发控制指令
                        SetSendData(device.Cancel());
                        SetSendData(device.Action(actionModel, packetModel.ControlModel.Seq, packetModel.ControlModel.ConfirmSeq));
                        logObj.Info($"SetSendData: 地址:{device}\t显示字符:{packetModel.ControlModel.Seq}");
                        break;
                    case CommunicationCmdTypeEnum.GET_LABEL_STATE:
                        SetSendData(device.LabelInfo());
                        break;
                    case CommunicationCmdTypeEnum.GET_LABEL_VOLTAGE:
                        SetSendData(device.GetBatteryVoltage());
                        break;
                }
            }
        }

        /// <summary>
        /// 通过DPS的连接key发送数据到DPS客户端
        /// </summary>
        /// <param name="iKey"></param>
        /// <param name="iModel"></param>
        private void SendDataToClientByKey(string iKey, ServerPacketModel iModel)
        {
            DataReceive(iKey, iModel);
        }

        /// <summary>
        /// 发送数据到DPS客户端
        /// </summary>
        /// <param name="deviceAddress">设备地址</param>
        /// <param name="iModel">服务端的数据包</param>
        private void SendDataToClient(string deviceAddress, ServerPacketModel iModel)
        {
            if (string.IsNullOrEmpty(deviceAddress) || !deviceAddressDictionary.ContainsKey(deviceAddress))
            {
                logObj.Error($"回送数据有误!控制器[{ipAddress}:{port}]未找到地址为{deviceAddress}对应的DPS连接!回送数据内容:[{iModel}]\r\n");
                return;
            }
            if (deviceAddressDictionary.ContainsKey(deviceAddress))
            {
                // 数据接收
                DataReceive(deviceAddressDictionary[deviceAddress], iModel);
            }
            else
            {
                logObj.Error($"向DPS客户端发送信息失败;地址:{deviceAddress},信息:{iModel}\r\n");
            }
        }

        /// <summary>
        /// 获取标签设备的动作信息
        /// </summary>
        /// <param name="iModel"></param>
        /// <returns></returns>
        private BaseLabelDevice GetLabelDeviceActionInfo(ServerPacketModel iModel)
        {
            EquipmentLabelTypeEnum type;
            if (iModel.CmdType == CommunicationCmdTypeEnum.ACTION) type = ((ActionPacketModel)iModel).LabelType;
            else if (iModel.CmdType == CommunicationCmdTypeEnum.GET_LABEL_VOLTAGE) type = ((GetDeviceVoltagePacketModel)iModel).LabelType;
            else return new BaseLabelDevice();
            switch (type)
            {
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2060:
                    return new MWU2060LabelDevice();
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2414:
                    return new MWU2414LabelDevice();
                case EquipmentLabelTypeEnum.AIOI_LABEL_NW2991:
                    return new NW2991LabelDevice();
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2402:
                    return new MWU2402LabelDevice();
            }
            return new BaseLabelDevice();
        }

        /// <summary>
        /// 获取标签设备的动作信息
        /// </summary>
        /// <param name="iModel"></param>
        /// <returns></returns>
        private BaseLabelDevice GetLabelDeviceActionInfo(ActionPacketModel iModel)
        {
            switch (iModel.LabelType)
            {
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2060:
                    return new MWU2060LabelDevice();
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2414:
                    return new MWU2414LabelDevice();
                case EquipmentLabelTypeEnum.AIOI_LABEL_NW2991:
                    return new NW2991LabelDevice();
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2402:
                    return new MWU2402LabelDevice();
            }
            return new BaseLabelDevice();
        }

        /// <summary>
        /// 设备类型
        /// </summary>
        /// <param name="iLabelType"></param>
        /// <returns></returns>
        private ActionModelAbstract GetActionModel(EquipmentLabelTypeEnum iLabelType)
        {
            switch (iLabelType)
            {
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2060:
                    return new AioiActionModelMWU2060();
                case EquipmentLabelTypeEnum.AIOI_LABEL_NW2991:
                    return new AioiNWActionModelNW2991();
                case EquipmentLabelTypeEnum.AIOI_LABEL_MWU2402:
                    return new AioiActionModelMWU2402();
            }
            return new AioiBaseActionModel();
        }

        /// <summary>
        /// 获取心跳数据
        /// </summary>
        /// <returns></returns>
        public override byte[] GetHeartbeat() { return new BaseLabelDevice().Heartbeat(); }

        /// <summary>
        /// 从报文中获取连番号
        /// </summary>
        /// <param name="iDatas"></param>
        /// <returns></returns>
        private int GetSerialNoByPacket(byte[] iDatas)
        {
            string temp = DefaultEncoding.GetString(iDatas, 1, iDatas.Length - 2);// 去头去尾后的字符串
            return int.Parse(temp.Substring(0, 3));
        }

        /// <summary>
        /// 获取发送报文信息
        /// </summary>
        /// <param name="iData">完整报文,带头带尾的</param>
        /// <returns></returns>
        private string GetSendDataInfo(byte[] iData)
        {
            string strAction;
            // 去头去尾
            string temp = DefaultEncoding.GetString(iData.Skip(1).Take(iData.Length - 2).ToArray());
            AioiActionPacketModel actionPacket = new AioiActionPacketModel();
            actionPacket.Unserialize(temp);
            if (string.IsNullOrEmpty(actionPacket.CmdType))
            {
                return null;
            }
            switch (actionPacket.CmdType)
            {
                case "I":
                    strAction = "Action:HeartBeat";
                    break;
                case "Z":
                    strAction = "Action:Init";
                    break;
                case "D":
                    strAction = $"Action:Cancel,Address:{actionPacket.Address}";
                    break;
                default:
                    strAction = $"Action:{actionPacket.CmdType}";
                    break;
            }
            return strAction;

        }

        ///// <summary>
        ///// 检查设备返回超时
        ///// </summary>
        //private void CheckDeviceResult(object obj)
        //{
        //    // 连不上跳过
        //    if (!connectionState) return;
        //    if (serialRespondDictionary == null || serialRespondDictionary.Count == 0) return;
        //    foreach (AioiSendSerialConnectionModel iModel in serialRespondDictionary.Values)
        //    {
        //        if (iModel.ConnectionSerialNo == -1) continue;
        //        if ((DateTime.Now - iModel.SendDateTime).TotalSeconds > 5)
        //        {
        //            if (!sendDataDictionary.ContainsKey(iModel.ConnectionSerialNo)) continue;
        //            // 从追溯报文字典中找出对应的设备地址
        //            string errorMsg = $"{DateTime.Now} <> 序列号[{iModel.ConnectionSerialNo}]没有收到控制器应答 --> ";
        //            errorMsg += ByteUtils.ByteArrayToAsciiString(sendDataDictionary[iModel.ConnectionSerialNo]);
        //            logObj.Error($"{errorMsg}\r\n");
        //            string sendStr = DefaultEncoding.GetString(sendDataDictionary[iModel.ConnectionSerialNo], 1, sendDataDictionary[iModel.ConnectionSerialNo].Length - 2);// 去头去尾后的字符串
        //            AioiActionPacketModel sendPacket = new AioiActionPacketModel();
        //            sendPacket.Unserialize(sendStr);
        //            if (!string.IsNullOrEmpty(sendPacket.Address))
        //            {
        //                // 发送异常信息到连接客户端
        //                SendDataToClient(sendPacket.Address, new ExceptionInfoPacketModel
        //                {
        //                    Address = sendPacket.Address,
        //                    ExceptionCode = ControllerExceptionCodeEnum.LABEL_OFFLINE,
        //                    IpAddress = ipAddress,
        //                    Port = port
        //                });
        //            }

        //        }
        //    }
        //}
    }

    /// <summary>
    /// 爱鸥发送连番号关联模型
    /// </summary>
    internal class AioiSendSerialConnectionModel
    {
        /// <summary>
        /// 关联连番号
        /// </summary>
        public int ConnectionSerialNo { get; set; }
        /// <summary>
        /// 发送时间
        /// </summary>
        public DateTime SendDateTime { get; set; }
    }
}
